﻿using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;

namespace Common
{
    /// <summary>
    /// 一些类型转换的函数。Int IsMy_yxh
    /// </summary>
    public static partial class ValueProc
    {
        public class DbTypeDict
        {
            public DbType DbType { get; set; }
            public Type CsType { get; set; }
            public string SqlType { get; set; }

            public DbTypeDict(DbType dbtyp, Type cstype, string sqltype)
            {
                this.DbType = dbtyp;
                this.CsType = cstype;
                this.SqlType = sqltype;
            }
        }

        internal class TypedDbTypeDict<T> : DbTypeDict
        {
            public TypedDbTypeDict(DbType dbtyp, string sqltype)
                : base(dbtyp, typeof(T), sqltype)
            {
            }
        }

        /// <summary>
        /// DbType , Type , SqlType 对应表.
        /// </summary>
        /// <returns></returns>
        public static List<DbTypeDict> GetDbTypeDict()
        {
            List<DbTypeDict> dict = new List<DbTypeDict>();

            dict.Add(new TypedDbTypeDict<string>(DbType.AnsiString, "varchar"));
            dict.Add(new TypedDbTypeDict<string>(DbType.AnsiStringFixedLength, "varchar"));
            dict.Add(new TypedDbTypeDict<string>(DbType.AnsiStringFixedLength, "char"));
            dict.Add(new TypedDbTypeDict<string>(DbType.AnsiStringFixedLength, "nchar"));
            dict.Add(new TypedDbTypeDict<string>(DbType.AnsiString, "nvarchar")); 
            
            dict.Add(new TypedDbTypeDict<Guid>(DbType.Guid, "uniqueidentifier"));
            dict.Add(new TypedDbTypeDict<string>(DbType.String, "text"));
            dict.Add(new TypedDbTypeDict<string>(DbType.String, "ntext"));
            dict.Add(new TypedDbTypeDict<string>(DbType.StringFixedLength, "varchar"));
            dict.Add(new TypedDbTypeDict<string>(DbType.Xml, "xml"));

            dict.Add(new TypedDbTypeDict<Byte[]>(DbType.Binary, "varbinary"));
            dict.Add(new TypedDbTypeDict<Byte[]>(DbType.Binary, "image"));

            dict.Add(new TypedDbTypeDict<Boolean>(DbType.Boolean, "bit"));
            dict.Add(new TypedDbTypeDict<Byte>(DbType.Byte, "samllint"));
            dict.Add(new TypedDbTypeDict<Decimal>(DbType.Currency, "money"));
            dict.Add(new TypedDbTypeDict<Decimal>(DbType.Decimal, "decimal"));
            dict.Add(new TypedDbTypeDict<Decimal>(DbType.VarNumeric, "decimal"));

            dict.Add(new TypedDbTypeDict<DateTime>(DbType.Date, "datetime"));
            dict.Add(new TypedDbTypeDict<DateTime>(DbType.DateTime, "datetime"));
            dict.Add(new TypedDbTypeDict<DateTime>(DbType.DateTime2, "datetime"));
            dict.Add(new TypedDbTypeDict<DateTime>(DbType.DateTimeOffset, "datetime"));
            dict.Add(new TypedDbTypeDict<DateTime>(DbType.Time, "datetime"));

            dict.Add(new TypedDbTypeDict<Double>(DbType.Double, "bigint"));
            dict.Add(new TypedDbTypeDict<Int16>(DbType.Int16, "smallint"));
            dict.Add(new TypedDbTypeDict<Int32>(DbType.Int32, "int"));
            dict.Add(new TypedDbTypeDict<Int64>(DbType.Int64, "bigint"));
            dict.Add(new TypedDbTypeDict<Object>(DbType.Object, "varbinary"));
            dict.Add(new TypedDbTypeDict<SByte>(DbType.SByte, "smallint"));
            dict.Add(new TypedDbTypeDict<Single>(DbType.Single, "float"));
            dict.Add(new TypedDbTypeDict<Single>(DbType.Single, "real"));
            dict.Add(new TypedDbTypeDict<UInt16>(DbType.UInt16, "smallint"));
            dict.Add(new TypedDbTypeDict<UInt32>(DbType.UInt32, "int"));
            dict.Add(new TypedDbTypeDict<UInt64>(DbType.UInt64, "bigint"));

            return dict;
        }

        public static DbType GetDbType(this Type type)
        {
            var dict = GetDbTypeDict().Where(o => o.CsType == type);
            if (dict.Count() == 0) return DbType.Object;
            return dict.First().DbType;
        }

        public static DbType GetDbType(string sqlType)
        {
            var dict = GetDbTypeDict().Where(o => string.Equals(o.SqlType, sqlType, StringComparison.CurrentCultureIgnoreCase));
            if (dict.Count() == 0) return DbType.Object;
            return dict.First().DbType;
        }

        public static bool DbTypeIsNumber(this DbType type)
        {
            return new DbType[] { 
                DbType.Byte ,
                DbType.Currency, 
                DbType.Decimal,
                DbType.VarNumeric , 
                DbType.Double, 
                DbType.Int16,  
                DbType.Int32, 
                DbType.Int64,  
                DbType.SByte,  
                DbType.Single, 
                DbType.UInt16, 
                DbType.UInt32, 
                DbType.UInt64, 
            }.Contains(type);
        }
    }
}
